#pragma once

#ifndef HIPPOWERKS_ENGINE_H
#define HIPPOWERKS_ENGINE_H
#define _HW_VER_ "0.1"

#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <time.h>

namespace HW
{
#include "typedefs.h"

#include "constants.h"

//******************************************************************************
//****																		****
//****						Engine Interface Commands						****
//****																		****
//******************************************************************************
int Initialize(int allowenginedebug=1);
int Terminate(void);


//******************************************************************************
//****																		****
//****							Graphics Commands							****
//****																		****
//******************************************************************************
int Graphics(int width=640, int height=480, int depth=0, int hertz=60, int flags=GRAPHICS_BACKBUFFER|GRAPHICS_DEPTHBUFFER);
void Flip(int sync=1);
int GraphicsWidth(void);
int GraphicsHeight(void);
int GraphicsModeExists(int width, int height, int depth, int hertz);
int GetGraphicsVendor(void);
int GetShaderModel(void);


//******************************************************************************
//****																		****
//****							 Input Commands								****
//****																		****
//******************************************************************************
int KeyHit(int key=KEY_ESCAPE);
int KeyDown(int key=KEY_SPACE);
int GetChar(void);
void FlushKeys(void);
int MouseHit(int button=1);
int MouseDown(int button=2);
int MouseX(void);
int MouseY(void);
int MouseZ(void);
void MoveMouse(int x, int y);
void HideMouse(void);
void ShowMouse(void);
void FlushMouse(void);


//******************************************************************************
//****																		****
//****							Timing Commands								****
//****																		****
//******************************************************************************
float FPS(void);
float UPS(void);
float AppSpeed(void);
float AppTime(void);
void UpdateAppTime(void);
void PauseApp(void);
void ResumeApp(void);
int AppSuspended(void);


//******************************************************************************
//****																		****
//****						 Miscellaneous Commands							****
//****																		****
//******************************************************************************
void RegisterAbstractPath(const_str path);
const_str AbstractPath(const_str path);
void SetZipStreamPassword(const_str url, const_str password);
int AppTerminate(void);
void SetAppTitle(const_str title);
void AppLog(const_str text, int flags=APPLOG_NORMAL);
void AppLogMode(int mode=1);
void MakeFPSGame(void);

//******************************************************************************
//****																		****
//****							 Texture Commands							****
//****																		****
//******************************************************************************
TTexture CreateTexture(int width=1024, int height=1024, int format=TEXTURE_RGBA);
TTexture LoadTexture(const_str name);
void ClampTexture(TTexture texture, int x=1, int y=1, int z=1);
void TFilter(int mode=1);
void AFilter(int mode=4);
int MaxAFilter(void);
long TextureWidth(TTexture texture);
long TextureHeight(TTexture texture);
void TextureFilter(TTexture texture, int filter);
str TextureName(TTexture texture);
void BindTexture(TTexture texture, int texunit=0);
void FreeTexture(TTexture texture);
int MaxTextureUnits(void);
void SetTextureQuality(int quality=1);

//******************************************************************************
//****																		****
//****							 Buffer Commands							****
//****																		****
//******************************************************************************
TBuffer CreateBuffer(int width=640, int height=480, int flags=BUFFER_COLOR|BUFFER_DEPTH);
TBuffer BackBuffer(void);
int BufferWidth(TBuffer buffer);
int BufferHeight(TBuffer buffer);
void SetBuffer(TBuffer buffer);
int MaxColorBuffers(void);
TTexture GetColorBuffer(TBuffer buffer, int n=0);
TTexture GetDepthBuffer(TBuffer buffer);
TBuffer CreateCustomBuffer(byte* GetSize, byte* MakeCurrent);
int SaveBuffer(TBuffer buffer, const_str name, int quality=85);
void ClearBuffer(int clsmode=BUFFER_DEPTH|BUFFER_COLOR0|BUFFER_COLOR1|BUFFER_COLOR2|BUFFER_COLOR3);
void FreeBuffer(TBuffer buffer);
TBuffer CurrentBuffer(void);
void CopyBuffer(TBuffer src, TBuffer dst, int components=BUFFER_DEPTH|BUFFER_COLOR0|BUFFER_COLOR1|BUFFER_COLOR2|BUFFER_COLOR3);
int SetColorBuffer(TBuffer buffer, TTexture texture, int index=0, int cubeface=0);
int SetDepthBuffer(TBuffer buffer, TTexture texture);

//******************************************************************************
//****																		****
//****							 Shader Commands							****
//****																		****
//******************************************************************************
TShader LoadShader(const_str vertpath, const_str fragpath="", const_str defines="");
void SetShader(TShader shader);
void SetShaderInt(TShader shader, const_str name, int value=1);
void SetShaderIntArray(TShader shader, const_str name, int* ar, int count=1);
void SetShaderFloat(TShader shader, const_str name, flt value=1);
void SetShaderFloatArray(TShader shader, const_str name, flt* ar, int count=1);
void SetShaderVec2(TShader shader, const_str name, const TVec2 &value, int count=1);
void SetShaderVec3(TShader shader, const_str name, const TVec3 &value, int count=1);
void SetShaderVec4(TShader shader, const_str name, const TVec4 &value, int count=1);
void FreeShader(TShader shader);
void SetShaderMat3(TShader shader, const_str name, const TVec9 &value, int count=1);
void SetShaderMat4(TShader shader, const_str name, const TVec16 &value, int count=1);

//******************************************************************************
//****																		****
//****							Material Commands							****
//****																		****
//******************************************************************************
TMaterial CreateMaterial(void);
TMaterial LoadMaterial(const_str name);
const_str MaterialName(TMaterial material);
void SetMaterialTexture(TMaterial material, TTexture texture, int stage=0);
TTexture GetMaterialTexture(TMaterial material, int stage=0);
void SetMaterialShader(TMaterial material, TShader shader, int shadow=0);
TShader GetMaterialShader(TMaterial material, int shadow=0);
void SetMaterialColor(TMaterial material, const TVec4 &color=Vec4(1));
void SetMaterialCallback(TMaterial material, BP callback, int callbackID=1);
void SetMaterialKey(TMaterial material, const_str key, const_str value);
str GetMaterialKey(TMaterial material, const_str key);
void FreeMaterial(TMaterial material);


//******************************************************************************
//****																		****
//****							 Surface Commands							****
//****																		****
//******************************************************************************
TSurface CreateSurface(TMesh mesh, TMaterial material=NULL);
long CountSurfaces(TMesh mesh);
TSurface GetSurface(TMesh mesh, int index=1);
TSurface FindSurface(TMesh mesh, TMaterial material=NULL);
void PaintSurface(TSurface surface, TMaterial material=NULL);
long CountVertices(TSurface surface);
long CountTriangles(TSurface surface);
long AddVertex(TSurface surface, const TVec3 &position, const TVec3 &normal=Vec3(0), const TVec2 &textureUV=Vec2(0));
long AddTriangle(TSurface surface, int vertex0, int vertex1, int vertex2);
void SetVertexPosition(TSurface surface, int vertex, const TVec3 &position);
void SetVertexNormal(TSurface surface, int vertex, const TVec3 &normal);
void SetVertexTexCoords(TSurface surface, int vertex, const TVec2 &textureUV, int texcoordset=0);
TVec3 GetVertexPosition(TSurface surface, int vertex=0);
TVec3 GetVertexNormal(TSurface surface, int vertex=0);
TVec2 GetVertexTexCoords(TSurface surface, int vertex=0, int texcoordset=0);
long TriangleVertex(TSurface surface, int triangle=0, int corner=0);
TMaterial GetSurfaceMaterial(TSurface surface);
TVec4 GetVertexColor(TSurface surface, int vertex=0);
void SetVertexColor(TSurface surface, int vertex=0, const TVec4 &color=Vec4(1));

//******************************************************************************
//****																		****
//****							Drawing Commands							****
//****																		****
//******************************************************************************
void Plot(int x=0, int y=0);
TFont LoadFont(const_str name);
void SetFont(TFont font);
void FreeFont(TFont font);
void DrawLine(int x1=0, int y1=0, int x2=100, int y2=100);
void DrawRect(int x=0, int y=0, int width=100, int height=100);
void SetBlend(int blendmode=BLEND_NONE);
void DrawText(int x, int y, const_str text, ...);
void SetColor(const TVec4 &color=Vec4(1));
void SetColor(flt r, flt g, flt b, flt a=1);
void DrawImage(TTexture texture, int x=0, int y=0, int width=-1, int height=-1);
int TextWidth(const_str text);
int FontHeight(void);


//******************************************************************************
//****																		****
//****							 World Commands								****
//****																		****
//******************************************************************************
TWorld CreateWorld(void);
void SetWorld(TWorld world);
void SetWorldSize(const TVec3 &size);
void SetWorldCullRange(flt nearrange=50, flt mediumrange=250, flt farrange=500);
void ClearWorld(void);
void FreeWorld(TWorld world);
TWorld CurrentWorld(void);
void UpdateWorld(float stepsize=1);
void RenderWorld(int elements=ENTITY_RENDERABLE);
TEntity LoadScene(const_str name);


//******************************************************************************
//****																		****
//****							 Entity Commands							****
//****																		****
//******************************************************************************
void SetEntityMatrix(TEntity entity, const TVec16 &matrix);
TVec16 GetEntityMatrix(TEntity entity);
void ScaleEntity(TEntity entity, const TVec3 &scale=Vec3(1));
void MoveEntity(TEntity entity, const TVec3 &direction=Vec3(1), int global=0);
void TurnEntity(TEntity entity, const TVec3 &angle=Vec3(1), int global=0);
void PositionEntity(TEntity entity, const TVec3 &position=Vec3(0), int global=0);
void RotateEntity(TEntity entity, const TVec3 &angle=Vec3(0), int global=0);
TVec3 EntityRotation(TEntity entity, int global=0);
TVec3 EntityPosition(TEntity entity, int global=0);
TVec3 EntityScale(TEntity entity);
TVec4 EntityQuat(TEntity entity);
flt EntityDistance(TEntity entity1, TEntity entity2);
void TranslateEntity(TEntity entity, const TVec3 &position=Vec3(0), int global=0);
void AlignToVector(TEntity entity, const TVec3 &vector, int axis=3, flt rate=1, flt roll=0);
void PointEntity(TEntity entity1, TEntity entity2, int axis=3, flt rate=1, flt roll=0);

int CountChildren(TEntity entity);
TEntity GetChild(TEntity entity, int index=1);
void EntityParent(TEntity entity, TEntity parent=NULL, int global=1);
TEntity GetParent(TEntity entity);
TEntity FindChild(TEntity entity, const_str name);

void PaintEntity(TEntity entity, TMaterial material, int recursive=0);
TMaterial GetEntityMaterial(TEntity entity);
void EntityColor(TEntity entity, const TVec4 &color=Vec4(1), int recursive=0);
TVec4 GetEntityColor(TEntity entity);
void EntityShadowMode(TEntity entity, int mode=1, int recursive=0);
void EntityShadowRange(TEntity entity, flt range=100, int recursive=0);

void Animate(TEntity entity, flt frame=0, flt blend=1, int sequence=0, int recursive=1);
int LoadAnimation(TEntity entity, const_str name="idle");
int CountAnimations(TEntity entity);
int AnimationLength(TEntity entity, int sequence=0);
void ClearAnimation(TEntity entity);

void EntityOrder(TEntity entity, int order=0, int recursive=0);

int EntityExists(TEntity entity);
void FreeEntity(TEntity entity);

void EmitSound(TEntity entity, TSound sound, flt range=50, flt volume=10, int flags=0);

TEntity CopyEntity(TEntity entity, int recursive=1);
void CopyEntityKeys(TEntity src, TEntity dst);
void SetEntityKey(TEntity entity, const_str hkey, const_str hvalue="1");
str GetEntityKey(TEntity entity, const_str hkey, const_str defaultvalue="");

void EntityType(TEntity entity, int collisionType=1, int recursive=0);
int GetEntityType(TEntity entity);

void EntityOcclusionMode(TEntity entity, int mode, int recursive=0);
void OcclusionCulling(int mode=1);
int EntityCulled(TEntity entity, TCamera camera);
void EntityViewRange(TEntity entity, int range=VIEWRANGE_NEAR, int recursive=0);
TVec6 GetEntityAABB(TEntity entity);
void HideEntity(TEntity entity);
void ShowEntity(TEntity entity);
int EntityHidden(TEntity entity);

void SetEntityUserData(TEntity entity, byte* data=NULL);
byte* GetEntityUserData(TEntity entity);
void SetEntityCallback(TEntity entity, byte* callback, int id=ENTITYCALLBACK_FREE);
void SetEntityTarget(TEntity entity, TEntity target, int index=0);
TEntity GetEntityTarget(TEntity entity, int index=0);
void SendEntityMessage(TEntity entity, const_str name, byte* extra=NULL, int delay=0);

void ForEachEntityDo(byte* function, byte* extra=NULL, int classes=ENTITY_ALL);
void ForEachEntityInAABBDo(const TVec6 &aabb, byte* callback, byte* extra=NULL, int entityclass=ENTITY_ALL);

void DebugEntities(int mode=1);


//******************************************************************************
//****																		****
//****							 Pivot Commands								****
//****																		****
//******************************************************************************
TPivot CreatePivot(TEntity parent=NULL);

//******************************************************************************
//****																		****
//****							ClipPlane Commands							****
//****																		****
//******************************************************************************
void SetCameraClipPlane(TCamera camera, int n, const TVec4 &plane);


//******************************************************************************
//****																		****
//****							 Camera Commands							****
//****																		****
//******************************************************************************
TCamera CreateCamera(TEntity parent=NULL);
void CameraClearMode(TCamera camera, int mode);
void CameraClearColor(TCamera camera, const TVec4 &color);
void CameraRange(TCamera camera, flt nearrange, flt farrange);
void CameraProjMode(TCamera camera, int projmode);
void CameraZoom(TCamera camera, flt zoom);
TVec3 CameraProject(TCamera camera, const TVec3 &position=Vec3(0));
TVec3 CameraUnproject(TCamera camera, const TVec3 &position=Vec3(0));
void GetCameraRange(TCamera camera, flt &nearRange, flt &farRange);

//******************************************************************************
//****																		****
//****							  Mesh Commands								****
//****																		****
//******************************************************************************
TMesh CreateMesh(TEntity parent=NULL);
TMesh LoadMesh(const_str name, TEntity parent=NULL);
str MeshName(TMesh mesh);
void ScaleMesh(TMesh mesh, const TVec3 &scale=Vec3(1));
void RotateMesh(TMesh mesh, const TVec3 &rotation);
void TranslateMesh(TMesh mesh, const TVec3 &position);
void UpdateMesh(TMesh mesh);
TMesh CreateCube(TEntity parent=NULL);
TMesh CreatePlane(TEntity parent=NULL);
TMesh CreateSphere(int segments=8, TEntity parent=NULL);
TMesh CreateCylinder(int segments=8, int solid=1, TEntity parent=NULL);
TMesh CreateCone(int segments=8, int solid=1, TEntity parent=NULL);
TMesh CreateDecal(TSurface surface, const TVec3 &position, flt radius, int maxtris=0);
void AddMesh(TMesh src, TMesh dst);

}


#endif // #ifndef HIPPOWERKS_ENGINE_H